# -*- coding: utf-8 -*-
'''
考虑如下path:

uri格式                                         本地格式或解释
file://d:/app/                            d:\app
file://chen-peng/h                        \\chen-peng\h
pop3://chen:password@gmail.com/a/b.txt    在chen的gmail邮箱中的/a/b.txt
'''

import os
import re

class Path(object):
    def __init__(self,scheme=None,device=None,host=None,segments=[]):
        self._scheme=scheme
        self._device=device
        self._host=host
        self._segments=segments
        
    @staticmethod
    def parse(str):
        '''client请使用path.Path()构造'''
        for rePathFormat,parser in _parsers.items():
            if rePathFormat.match(str):
                 return parser.parse(str)
        return _RelativePath.parse(str)
    
    def getSegments(self):
        return self._segments[:]
    
    def getSegmentCount(self):
        return len(self._segments)
    
    def getLastSegment(self):
        return self._segments[-1]
    
    def getParent(self):
        if len(self._segments) == 0:
            return None
        
        segments=self._segments[0:-1]
        return type(self)(scheme=self._scheme,device=self._device,host=self._host,segments=segments) 
    
    def __repr__(self):
        return str(self)
    
    def __ne__(self,other): 
        return not self.__eq__(other)
    
    def __eq__(self,other):
        if other is None or not isinstance(other,Path):
            return False
        
        return self._scheme == other._scheme \
           and self._device == other._device \
           and self._host == other._host\
           and self._segments == other._segments 
    
    def __hash__(self):
        return hash(str(self))
    
    #todo remove
    def append(self,other):
        return self + other
    
    def __add__(self,other):
        '''
        __add__(str other) -> Path
        __add__(Path other) -> Path
        
        self     other   result
        d:/a  +  b/c ->  d:/a/b/c
        '''
        if isinstance(other,str):
            other=Path.parse(other)
        assert not other.isAbsolute(),"only can append relative path!"
        
        segments=self._segments[:]
        segments.extend(other._segments)
        return type(self)(scheme=self._scheme,device=self._device,host=self._host,segments=segments)
    
    
    def __sub__(self,other):
        """
        
        self         other    result
        d:/a/b/c  -  d:/a ->  b/c
        """
        if isinstance(other,str):
            other=Path.parse(other)
            
        assert other.isPrefixOf(self) ,"only can subtract more little path!"
        
        segments=self._segments[len(other._segments):]
        return _RelativePath(segments=segments)
    
    def scheme(self):
        return self._scheme
    
    def host(self):
        return self._host
    
    def uri(self):
        if type(self) is _RelativePath :
            return None
        
        hostOrDevice=self._device if self._device != None else self._host
        return "%s://%s/%s" % (self._scheme,hostOrDevice ,_SEPARATOR.join(self._segments)) 
    
    def isAbsolute(self):
        return False if type(self) is _RelativePath else True
    
    def isPrefixOf(self,other):
        if not (self._scheme == other._scheme \
           and self._device == other._device \
           and self._host == other._host):
           return False
        if len(self._segments)>len(other._segments):
            return False
        for i in range(len(self._segments)):
            if self._segments[i] != other._segments[i]:
                return False
        return True
        
        
class _WindowAbsolutePath(Path):
    @staticmethod
    def parse(str):
        device,path = os.path.splitdrive(str)
        return _WindowAbsolutePath(scheme="file",device=device,segments=_RelativePath.split(path))
    
    def __str__(self):
        return r"%s%s" % (self._device+os.path.sep,os.path.sep.join(self._segments))  
    
class _RelativePath(Path):
    
    @staticmethod
    def split(str):
        """
        split(str) -> list
        
        split("a/b/c") -> ["a","b","c"]
        """
        return [segment for segment in _reSegments.split(str) if len(segment)!=0]

    @staticmethod
    def parse(str):
        return _RelativePath(segments=_RelativePath.split(str))
 
    def __str__(self):
        return _SEPARATOR.join(self._segments)

    
class _UncPath(object):

    @staticmethod
    def parse(str):
        pass
 
class _UriPath(object):

    @staticmethod
    def parse(str):
        pass
    
_SEPARATOR = '/'
_SEPARATOR_WINDOWS = "\\"

_reSegments = re.compile(r"\\+|/+") # "a/b\c" -> ["a","b","c"]

#path type check
__reWindowsAbsolutePath=re.compile(r"^[a-zA-Z]:")
__reUnc=re.compile(r"^\\\\")
__reUri=re.compile(r"^\w+://")
_parsers={__reWindowsAbsolutePath:_WindowAbsolutePath,
         __reUnc:_UncPath,
         __reUri:_UriPath}
